import { ConfigEnv, loadEnv, PluginOption, UserConfigExport } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import vueJsx from '@vitejs/plugin-vue-jsx'
import {
  createStyleImportPlugin,
  ElementPlusResolve,
} from 'vite-plugin-style-import'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import eslintPlugin from 'vite-plugin-eslint'
import { visualizer } from 'rollup-plugin-visualizer'
import Inspect from 'vite-plugin-inspect'
import { viteMockServe } from 'vite-plugin-mock'
import removeConsole from 'vite-plugin-remove-console'
import legacy from '@vitejs/plugin-legacy'
import { viteVConsole } from 'vite-plugin-vconsole'
import viteCompression from 'vite-plugin-compression'
import { chunkSplitPlugin } from 'vite-plugin-chunk-split'
// @ts-ignore
import packageInfo from './package.json'

function _resolve(dir: string) {
  return path.resolve(__dirname, dir)
}

/**
 * val值是否为字符串'true'
 *
 * @param   {string}  val  [val description]
 *
 * @return  {[type]}       [return description]
 */
function envStrValIsTrue(val: string | undefined | null) {
  return val === 'true'
}

export default ({ command, mode }: ConfigEnv): UserConfigExport => {
  const root = process.cwd()
  // 读取.env中配置的环境变量
  const env = loadEnv(mode, root)
  console.log(
    '执行命令: ',
    command,
    ', mode:',
    mode,
    ', env配置文件数据: ',
    env
  )

  // 其他可选插件
  const otherPlugins: (PluginOption | PluginOption[])[] = []
  // 是否进行包分析
  if (envStrValIsTrue(env.VITE_PACKAGE_ANALYZER)) {
    // 启用包分析
    otherPlugins.push(
      visualizer({
        filename: './node_modules/.cache/visualizer/stats.html',
        open: true,
        gzipSize: true,
        brotliSize: true,
      })
    )
  }
  // 是否启用VConsole插件
  if (envStrValIsTrue(env.VITE_ENABLE_VCONSOLE)) {
    otherPlugins.push(
      viteVConsole({
        entry: path.resolve('src/main.ts'), // 或者可以使用这个配置: [path.resolve('src/main.ts')]
        localEnabled: true,
        enabled: true,
        config: {
          maxLogNumber: 1000,
          theme: 'dark',
        },
      })
    )
  }
  if (command === 'serve' || mode === 'development') {
    otherPlugins.push(Inspect())
    otherPlugins.push(
      viteMockServe({
        // default
        mockPath: 'mock',
        localEnabled: true,
      })
    )
  } else {
    if (envStrValIsTrue(env.VITE_REMOVE_CONSOLE)) {
      otherPlugins.push(removeConsole())
    }
    otherPlugins.push(
      /*
      该插件用于最终的打包文件进行分包
      如这个配置: 'vue-base-vendor': ['axios', 'pinia', 'vue', 'vue-router'],
      是将'axios', 'pinia', 'vue', 'vue-router'这4个包打包成名为vue-base-vendor的包。
      如何进行分包：
      1. 大文件要分包
      2. 基本不变的内容要分包
      3. 分包要适度，也不要拆分太多的包
      通常会对哪些东西拆包？
      1. vendor.js vite默认会将node_modules下的所有依赖打包成一个vendor.js文件，这个文件通常会很大，因此需要拆包

      // important: 如果package.json中没有的包不要配置在这个组件里面，否则会报错: TypeError: Cannot destructure property 'dir' of 'object null' as it is null
       */
      chunkSplitPlugin({
        strategy: 'default',
        customSplitting: {
          'vue-base-vendor': ['axios', 'pinia', 'vue', 'vue-router'],
          'web-vendor': ['@vueuse/core', 'js-cookie', 'vue-request', 'dayjs'],
          'ui-framework': [
            'vxe-table',
            'xe-utils',
            'element-plus',
            '@element-plus/icons-vue',
          ],
        },
      })
    )
    otherPlugins.push(
      /*
      该插件用于在原打包结果文件基础上再对原始文件进行gz压缩，并形成额外的gz文件。
      nginx也有gzip功能，为什么前端还要打包成gz文件? 
      nginx是动态生成gz文件，前端打包是静态生成gz文件，极端情况，能节省服务器的计算资源
       */
      viteCompression({
        // 是否在控制台输出压缩结果
        verbose: true,
        // 如果不想压缩某个文件：则启用下面这个方法，通过file判断文件名，返回true和false控制是否压缩
        // filter:(file:string)=>true
        // 大于50kb才压缩
        threshold: 51200,
      })
    )
    // 解决vue3对低版本浏览器的兼容性
    otherPlugins.push(
      legacy({
        targets: packageInfo.browserslist, //需要兼容的浏览器以及对应版本，统一配置在了package.json的browserslist
        additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
      })
    )
  }
  const resultConfig: UserConfigExport = {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: `@use "@/assets/scss/_vars.scss" as *;
          @use "@/assets/scss/_mixins.scss" as *;`,
        },
      },
    },
    plugins: [
      vue(),
      vueJsx(),
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')],
        // 指定symbolId格式
        symbolId: 'icon-[dir]-[name]',
      }),
      eslintPlugin({
        include: [
          'src/**/*.ts',
          'src/**/*.vue',
          'src/*.ts',
          'src/*.vue',
          'src/*.js',
          'src/**/*.jsx',
          'src/**/*.txs',
          'src/*.jsx',
          'src/*.tsx',
        ],
        cache: false,
      }),
      // 解决类Message组件样式无法自动引入问题
      createStyleImportPlugin({
        resolves: [ElementPlusResolve()],
        libs: [
          {
            libraryName: 'element-plus',
            esModule: true,
            resolveStyle: (name: string) => {
              return `element-plus/theme-chalk/${name}.css`
            },
          },
        ],
      }),
      AutoImport({
        resolvers: [ElementPlusResolver()],
        dts: './src/auto-imports.d.ts',
        eslintrc: {
          enabled: true, // Default `false`
          filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`
          globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
        },
      }),
      Components({
        resolvers: [ElementPlusResolver()],
        dts: './src/components.d.ts',
      }),
      ...otherPlugins,
    ],
    // 默认为/, 用于发布在非根目录的时候需要设置该值
    base: env.VITE_PUBLIC_BASEPATH,
    server: {
      host: '0.0.0.0',
      port: 4200,
      open: true,
      // proxy: {
      //   '/api': {
      //     target: env.VITE_PROXY_TARGET,
      //     changeOrigin: true,
      //     rewrite: path => path.replace(/^\/api/, ''),
      //   },
      // },
    },
    resolve: {
      alias: {
        '@': _resolve('src'),
      },
    },
    build: {
      rollupOptions: {
        output: {
          // manualChunks: (id: string) => {
          //   if (id.includes('node_modules')) {
          //     return id
          //       .toString()
          //       .split('node_modules/')[1]
          //       .split('/')[0]
          //       .toString()
          //   }
          // },
          // // 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]表示该文件内容hash值
          // entryFileNames: 'js/[name].[hash].js', // 用于命名代码拆分时创建的共享块的输出命名
          // chunkFileNames: 'js/[name].[hash].js', // 用于输出静态资源的命名，[ext]表示文件扩展名
          assetFileNames: 'static/[ext]/[name].[hash].[ext]', // 拆分js到模块文件夹 // chunkFileNames: (chunkInfo) => { //     const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/') : []; //     const fileName = facadeModuleId[facadeModuleId.length - 2] || '[name]'; //     return `js/${fileName}/[name].[hash].js`; // },
        },
      },
    },
  }
  return resultConfig
}
